#include <iostream>
#include <string>
#include <strings.h>
#include <cstdio>
#include <cstdlib>
#include <cassert>
//网络四必须包
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//
#include <pthread.h>
#include <sys/socket.h>

using std::cout;
using std::endl;

void Usage(std::string name)
{
    cout << "Usage:\n\t" << name << " ip port" << endl;
}

void *recverServer(void *arg)
{
    cout<<"into thread"<<endl;
    while (true)
    {
        char buffer[1024];
        int sockfd = *(int *)arg;
        struct sockaddr_in tmp;
        socklen_t len = sizeof(tmp) - 1;
        ssize_t s = recvfrom(sockfd, buffer, sizeof(buffer),
                             0, (struct sockaddr *)&tmp, &len);
        if (s > 0)
        {
            cout << "server echo#" << buffer << endl;
        }
    }
    return nullptr;
}

// ./udpClient server_ip server_port
// 如果一个客户端要连接server必须知道server对应的ip和port
int main(int args, char *argv[])
{
    if (args != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    // 1. 根据传入的参数，得到要访问服务器数据
    std::string severr_ip = argv[1];
    uint16_t server_port = atoi(argv[2]);

    // 2. 创建客户端
    // 2.1创建Socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    assert(sockfd > 0);
    // 2.2 client 需不需要bind??? 需要bind，但是不需要用户自己bind，而是os自动给你bind
    // 所谓的"不需要"，指的是: 不需要用户自己bind端口信息！因为OS会自动给你绑定，你也最好这么做！
    // 如果我非要自己bind呢？可以！严重不推荐！
    // 所有的客户端软件 <-> 服务器 通信的时候，必须得有 client[ip:port] <-> server[ip:port]
    // 为什么呢？？client很多，不能给客户端bind指定的port，port可能被别的client使用了，你的client就无法启动了
    // 那么server凭什么要bind呢？？server提供的服务，必须被所有人知道！server不能随便改变！(网站名不能随意改变)
    // 2.2 填写服务器对应的信息
    struct sockaddr_in server;
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(severr_ip.c_str());

    //创建线程去接受服务器的消息
    pthread_t t;
    pthread_create(&t, nullptr, recverServer, (void *)&sockfd);

    // 3. cilent 向 server 通信
    std::string buffer;
    while (true)
    {
        cout << "Please Entet: ";
        getline(std::cin, buffer);
        //发送消息给服务器
        sendto(sockfd,buffer.c_str(),buffer.size(),0,
        (const struct sockaddr*)&server,sizeof(server));
    }
    return 0;
}